﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Data;
using System.Data.Entity;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using AutoMapper;
using DevWeb.Biztalk.DeploymentSettings.Common;
using DevWeb.Biztalk.DeploymentSettings.Data.CodeFirst;
using DevWeb.Biztalk.DeploymentSettings.DeploymentService.ClientProxy.ChannelPattern;
using DevWeb.Biztalk.DeploymentSettings.DeploymentService.Contracts;
using DevWeb.Biztalk.DeploymentSettings.WebUI.Models;
using DevWeb.Biztalk.DeploymentSettings.WebUI.Models.Export;
using Microsoft.Practices.Unity;



namespace DevWeb.Biztalk.DeploymentSettings.WebUI.Controllers
{
    public class IntegrationVersionController : BaseController
    {
        //
        // GET: /IntegrationVersion/



        public IntegrationVersionController()
        {
            
        }


        /// <summary>
        /// Show complete view of all Versions os a certain integration
        /// </summary>
        /// <returns></returns>
        public ActionResult Index(int? id)
        {

            


            List<IntegrationVersion> dbversions = null;
            if (id.HasValue)
            {

                var dbintegration = Context.Integrations.Include("IntegrationVersions").FirstOrDefault(p => p.Id == id);


                if (dbintegration == null)
                    throw new KeyNotFoundException("No integration found with Id : " + id.ToString());


                dbversions = dbintegration.IntegrationVersions.ToList();
                


            }
            else
            {
                var q = from iv in Context.IntegrationVersions
                   select iv;

                dbversions = q.Include(p => p.Integration).ToList();

            }

            var model = Mapper.Map<List<IntegrationVersionViewModel>>(dbversions);
            


            ViewBag.integrationID = id;
            ViewBag.IntegrationName = dbversions.FirstOrDefault().IntegrationName;
            return View(model);
        }

        /// <summary>
        /// Show complete view of all Versions os a certain integration
        /// </summary>
        /// <returns></returns>
        public ActionResult CreateVersion(int id)
        {


            var dbintegration = Context.Integrations.Include("IntegrationVersions").SingleOrDefault(p => p.Id.Equals(id));


            if (dbintegration == null)
                throw new ArgumentNullException("Integration not found with ID" + id.ToString(CultureInfo.InvariantCulture));


        
           var integrationversionviewmodel =     GetNewintegrationversionviewmodel(dbintegration);

          


            return View(integrationversionviewmodel);
        }

        private IntegrationVersionViewModel GetNewintegrationversionviewmodel(Integration dbintegration)
        {

            var latestversion = "1.0.0";
            var lastid = 0;

            if (dbintegration.IntegrationVersions.Count > 0)
            {
                var dbitem = dbintegration.IntegrationVersions.OrderByDescending(p => p.Id).FirstOrDefault();
                
                latestversion = dbitem.Version;
                lastid = dbitem.Id;

                int place = latestversion.LastIndexOf(".0");
                if (place != -1) {
                    latestversion = latestversion.Remove(place, 2).Insert(place, ".1");
                
                }
            }

            var integrationversionviewmodel = new IntegrationVersionViewModel()
            {
                ProductUpgradeCode = dbintegration.ProductUpgradeCode.ToString(),
                ProductId = Guid.NewGuid(),
                Version = latestversion,
                Description =string.Format("This is a new version of  {0} by {1} at {2}", dbintegration.Name, User.Identity.Name, DateTime.Now.ToString()),
                IntegrationId = dbintegration.Id,
                CreateDateTime = DateTime.Now,
                IntegrationName = dbintegration.Name,
                PreviousIntergrationVersionId =lastid 
            };

            return integrationversionviewmodel;
        }

        [HttpPost]
        public ActionResult CreateVersion(IntegrationVersionViewModel integrationVersionViewModel)
        {
            if (ModelState.IsValid)
            {

                
                var integrationVersionToSave = Mapper.Map<IntegrationVersion>(integrationVersionViewModel);

                var dbsettings = Context.IntegrationVersionParameters.AsNoTracking().Include("IntegrationVersionParameterValues").AsNoTracking().Where(p => p.IntegrationVersionId == integrationVersionViewModel.PreviousIntergrationVersionId).ToList();
                
                integrationVersionToSave.CreateDateTime = DateTime.Now;

                using (DbContextTransaction dbctx = Context.GetDatabase().BeginTransaction())
                {

                    Context.IntegrationVersions.Add(integrationVersionToSave);
                   
                    foreach (var param in dbsettings)
                    {
                        param.IntegrationVersion = integrationVersionToSave;
                        param.Id = 0;
                        Context.IntegrationVersionParameters.Add(param);
                      
                        foreach (var paramvalue in param.IntegrationVersionParameterValues)
                        {
                            
                            paramvalue.IntegrationVersionParameter = param;
                            paramvalue.IntegrationVersionParameterId = param.Id;
                            Context.IntegrationVersionParameterValues.Add(paramvalue);
                         
                        }

                    }
                    Context.SaveChanges(System.Web.HttpContext.Current.User.Identity.Name);
                    dbctx.Commit();
                }

                 
               



                

               
                
             
                return RedirectToAction("Index", "IntegrationVersionSetting",
                    new {id = integrationVersionToSave.Id});
            }


            return View(integrationVersionViewModel);
        }


       


        public ActionResult Edit(int id)
        {
            

            var dbversion = Context.IntegrationVersions.Include("Integration").SingleOrDefault(p => p.Id.Equals(id));


            var model = Mapper.Map<IntegrationVersionViewModel>(dbversion);


            return View(model);
        }

        [HttpPost]
        public ActionResult Edit(IntegrationVersionViewModel model)
        {
            if (ModelState.IsValid)
            {
                var selector = model.Id;

                var dbversion =
                    Context.IntegrationVersions.Include("Integration").SingleOrDefault(p => p.Id.Equals(selector));


                var updatemodel = Mapper.Map(model, dbversion);
                Context.SaveChanges(System.Web.HttpContext.Current.User.Identity.Name);

                return RedirectToAction("Index", new {id = updatemodel.Id});
            }
            else
            {
                return View(model);
            }
        }

        public ActionResult NotAllowed()
        {
            var version = TempData["version"];
            
            var model = Mapper.Map<IntegrationVersionViewModel>(version);
            return View(model);


        }

        public ActionResult Delete(int id)
        {


            var dbversion = Context.IntegrationVersions.Include("Integration").Include("DeploymentLogs").SingleOrDefault(p => p.Id.Equals(id));
            if (dbversion != null && dbversion.DeploymentLogs.Count > 0)
            {

                TempData["version"] = dbversion;
                return RedirectToAction("NotAllowed");
            }
            var model = Mapper.Map<IntegrationVersionViewModel>(dbversion);


            return View(model);
        }

        [HttpPost]
        public ActionResult Delete(IntegrationVersionViewModel model)
        {
            var dbversion =  Context.IntegrationVersions.SingleOrDefault(p => p.ProductId.Equals(model.ProductId));


            Context.IntegrationVersions.Remove(dbversion);
             Context.SaveChanges(System.Web.HttpContext.Current.User.Identity.Name);

            return RedirectToAction("Index", new {id = model.IntegrationId});
        }


        public ActionResult Export(int id)
        {

            var proxyclient = SetupProxyClient();

            ViewBag.RespositoryURL = proxyclient.ClientChannelBase.Endpoint.Address.Uri.ToString();

            var dbversion = Context.IntegrationVersions.Include("Integration").SingleOrDefault(p => p.Id.Equals(id));


            var model = Mapper.Map<IntegrationVersionViewModel>(dbversion);


            return View(model);
        }

        private static ProxyClient<IDeploymentSettingsService> SetupProxyClient()
        {
//get configuration from WebConfig
            var envSettingsRepositoryEndpointConfig = ConfigurationManager.AppSettings["EnvSettingsRepositoryEndpointConfig"];


            //setup nieuw client
            var proxyclient =
                new DeploymentService.ClientProxy.ChannelPattern.ProxyClient<IDeploymentSettingsService>(
                    envSettingsRepositoryEndpointConfig);
            return proxyclient;
        }

        [HttpPost]
        public ActionResult Export(IntegrationVersionViewModel model)
        {
            var proxyclient = SetupProxyClient();

            var dbversion =  Context.IntegrationVersions.Include("Integration").Include("IntegrationVersionParameters").Include("IntegrationVersionParameters.IntegrationVersionParameterValues").SingleOrDefault(p => p.Id.Equals(model.Id));

            if (dbversion != null)
            {
                dbversion.Integration.IntegrationVersions= null;


             


               // var integrationsaved = proxyclient.Client.ImportIntegrationVersionData(dbversion);
            }

            return RedirectToAction("Index", "Integration", new { id = model.IntegrationId });

          

        }

        public ActionResult ExportToFile(int id)
        {
            var dbversion =  Context.IntegrationVersions.Include("Integration").Include("IntegrationVersionParameters").Include("IntegrationVersionParameters.IntegrationVersionParameterValues").SingleOrDefault(p => p.Id.Equals(id));

            if (dbversion==null)
                throw new ArgumentException("There is nog Integration Version Found");
            //var model = Mapper.Map<IntegrationVersionViewModel>(dbversion);
            var model = new ExportModel(dbversion);
            var xmldata = Helpers.XmlSerialize(model);
            Stream memStream = new MemoryStream();

            xmldata.Save(memStream);

            byte[] fsbyte = new byte[memStream.Length];
            memStream.Seek(0, SeekOrigin.Begin);
            memStream.Position = 0;

            int br = memStream.Read(fsbyte, 0, fsbyte.Length);
            if (br != fsbyte.Length)
                throw new System.IO.IOException("error reading data from XML Data");
            var filename = string.Format("{0}-Version-{1}-ProductID-{2}.xml", dbversion.IntegrationName, dbversion.Version,
                dbversion.ProductId.ToString("d"));



            return  File(fsbyte, System.Net.Mime.MediaTypeNames.Text.Xml, filename);

        }

        public ActionResult ImportFromFile()
        {
            var model = TempData["fileimport"] as ExportModel;
            TempData["fileimport"] = model;
            return View(model);
        }

        [HttpPost]
        public ActionResult ConfirmImport()
        {

            var model = TempData["fileimport"] as ExportModel;

            var modeltossave = new IntegrationVersion();
            modeltossave.CreateDateTime = model.CreateDateTime;

            var targetenvs = Context.TargetEnvironments.ToLookup(p => p.Name);


           

          
            if (model != null)
            {
                var productupgradecode = model.ProductUpgradeCode;
                var parentintegration = Context.Integrations.SingleOrDefault(p => p.ProductUpgradeCode.Equals(productupgradecode));

                if (parentintegration != null)
                {
                    //Assign ID for current Parent
                    modeltossave.IntegrationId = parentintegration.Id;
                    modeltossave.Integration = parentintegration;
                    modeltossave.Integration.Description = model.IntegrationDescription;
                    
                }
                else
                {
                
                    ///new integration

                    var integrationtoadd =new Integration();
                    integrationtoadd.CreateDateTime = model.CreateDateTime;
                    integrationtoadd.Description = model.IntegrationDescription;
                    integrationtoadd.ProductUpgradeCode = productupgradecode;
                    integrationtoadd.Name = model.Name;
                    Context.Integrations.Add(integrationtoadd);
                    modeltossave.Integration = integrationtoadd;

                }
            }


            var dbversion = Context.IntegrationVersions.SingleOrDefault(p => p.ProductId.Equals(model.ProductId));
            if (dbversion == null)
            {
                modeltossave.Id = 0;
                modeltossave.ProductId = model.ProductId;
                modeltossave.Version = model.Version;
                modeltossave.Description = model.Description;
                modeltossave.CreateDateTime = model.CreateDateTime;

                Context.IntegrationVersions.Add(modeltossave);
               
            }

            else
            {
                ///dbversion already exists
                var message = string.Format("IntegrationVersion with ProductId {0} already Exist in DB",
                    dbversion.ProductId.ToString());
                throw new ArgumentException(message);
            }

            modeltossave.IntegrationVersionParameters = new Collection<IntegrationVersionParameter>();
            foreach (var exportParameter in model.ExportParameters)
            {
                
                IntegrationVersionParameter param = new IntegrationVersionParameter();
                param.CreateDateTime = model.CreateDateTime;
                param.IntegrationVersionParameterValues = new Collection<IntegrationVersionParameterValue>();
                param.ParameterName = exportParameter.ParameterName;
                param.DefaultValue = exportParameter.DefaultValue;
                param.IntegrationVersion = modeltossave;
                modeltossave.IntegrationVersionParameters.Add(param);
                foreach (var parameterValue in exportParameter.ParameterValues)
                {
                    IntegrationVersionParameterValue envvalue = new IntegrationVersionParameterValue();
                    envvalue.CreateDateTime = model.CreateDateTime;
                    var target = parameterValue.Environment;
                    if (targetenvs.Contains(target))
                    {
                        envvalue.TargetEnvironment = targetenvs[target].FirstOrDefault();
                        envvalue.Value = parameterValue.Value;
                        envvalue.CreateDateTime = DateTime.Now;
                    }
                    else
                    {
                        //environment dowsn;t yet exists
                        var newtargetenv = new TargetEnvironment();
                        newtargetenv.Name = parameterValue.Environment;
                        newtargetenv.Description =
                            string.Format("Created by Fileimport integrationversion ProductID {0} , Name {1}",
                                model.ProductId.ToString(), model.Name);
                        newtargetenv.CreateDateTime = DateTime.Now;

                        TargetEnvironment targetEnvironment = Context.TargetEnvironments.Add(newtargetenv);
                        envvalue.TargetEnvironment = targetEnvironment;
                    }

                    envvalue.Value = parameterValue.Value;
                    
                    param.IntegrationVersionParameterValues.Add(envvalue);
                }

            }
            Context.SaveChanges(System.Web.HttpContext.Current.User.Identity.Name);
            return RedirectToAction("Index", "Integration");
        }
    }
}